# use groundhog to make code maximally reproducible
if (!require("groundhog", quietly = TRUE)) {
install.packages("groundhog")
}
library("groundhog")
# use groundhog to install and load packages
pkgs <- c("here", # System path management
"tidyverse", # ggplot, dplyr, %>%, and friends
"tinytable", # Lightweight package to create tables
"modelsummary", # Data and model summaries with tables and plots
"pandoc", # Required for saving tables as docx
"hrbrthemes", # Additional ggplot themes
"extrafont", # Additional fonts for plots etc
"showtext", # So that fonts also work on mac
"patchwork" # Combine ggplot objects
)
groundhog.library(pkgs, "2024-07-01") Go / No-Go Preparations: Cognitive Control and Motivated Reasoning
Data Preparations
Add a new subj_idx to data_raw.
id_order <- unique(data_raw$`Participant Private ID`)
data_raw <- data_raw %>%
mutate(subj_idx = match(`Participant Private ID`, id_order))
id_table <- data_raw %>%
select(`Participant Private ID`, subj_idx) %>%
distinct()
# save the id table, so that we can use the same matches for the fake news task
id_dir <- here("01_data", "private_id_to_subj_idx.csv")
write_csv(id_table, id_dir,
na = "", append = FALSE, col_names = TRUE)Create numerical versions of the variables response and stimulus.
A go response is 1, and a no-go response is 0.
data_num <- data_raw %>%
select(subj_idx,
`Participant Private ID`:condition) %>%
rename(response_lab = response,
stimulus_lab = stimulus) %>%
mutate(response = if_else(response_lab == "nogo", 0, 1),
stimulus = if_else(stimulus_lab == "nogo", 0, 1))Also, the rt for no-go trials and missed go trials should be NA, and not 500 as it is now.
data_num <- data_num %>%
mutate(rt = if_else(response == 0, NA_real_, rt))Filter data
Remove practice trials
initial_rows <- nrow(data_num)
data_filtered <- data_num %>%
filter(!str_detect(trial_id, "^practice_"))
removed_practice <- initial_rows - nrow(data_filtered)
print(paste(removed_practice, "practice trials have been removed"))[1] "10080 practice trials have been removed"
Remove outliers
Responses with reaction times < 150 ms will be removed, as such fast reaction times are very unlikely to be actual responses and not just guesses.
outlier_num <- data_filtered %>%
filter(rt < 150) %>%
nrow()
outlier_per <- (outlier_num / nrow(data_filtered)) * 100
print(paste("There are", outlier_num, "trials with a rt < 150 ms, which is", round(outlier_per, 2), "% of the total number of trials =", nrow(data_num)))[1] "There are 1344 trials with a rt < 150 ms, which is 0.95 % of the total number of trials = 151200"
data_filtered <- data_filtered %>%
filter(is.na(rt) | rt >= 150)Accuracy, Commission Errors, Omission Errors
gng_performance <- data_filtered %>%
group_by(subj_idx) %>%
summarise(
commission_errors = sum(stimulus == 0 & response == 1, na.rm = TRUE),
omission_errors = sum(stimulus == 1 & response == 0, na.rm = TRUE),
go_accuracy = sum(stimulus == 1 & response == 1, na.rm = TRUE) / sum(stimulus == 1, na.rm = TRUE) * 100,
nogo_accuracy = sum(stimulus == 0 & response == 0, na.rm = TRUE) / sum(stimulus == 0, na.rm = TRUE) * 100,
overall_accuracy = sum(stimulus == response, na.rm = TRUE) / n() * 100,
rt_go_avg = mean(rt[stimulus == 1 & !is.na(rt)]),
rt_nogo_avg = mean(rt[stimulus == 0 & !is.na(rt)]),
)Reverse-coded commission errors
Add reverse-coded commission errors (this was not pre-registered, but to make interpretations more intuitive reverse-coding the commission errors will make it directionally aligned with the CRT correct score –> higher values indicate higher cognitive control)
gng_performance <- gng_performance %>%
mutate(commission_errors_r = 56 - commission_errors)Descriptive checks
How many and which participants have an accuracy below 50%?
gng_performance %>%
filter(overall_accuracy <= 50) %>%
tt()| subj_idx | commission_errors | omission_errors | go_accuracy | nogo_accuracy | overall_accuracy | rt_go_avg | rt_nogo_avg | commission_errors_r |
|---|---|---|---|---|---|---|---|---|
| 255 | 0 | 224 | 0.0 | 100.0 | 20.0 | NaN | NaN | 56 |
| 269 | 0 | 224 | 0.0 | 100.0 | 20.0 | NaN | NaN | 56 |
| 413 | 0 | 224 | 0.0 | 100.0 | 20.0 | NaN | NaN | 56 |
| 445 | 15 | 123 | 43.3 | 71.7 | 48.9 | 303 | 249 | 41 |
gng_performance %>%
filter(overall_accuracy <= 50) %>%
tt() %>%
save_tt(here("03_output", "tables", "gng_fails.docx"),
overwrite = TRUE)gng_performance %>%
select(commission_errors, commission_errors_r, omission_errors:rt_nogo_avg) %>%
datasummary_skim()| Unique | Missing Pct. | Mean | SD | Min | Median | Max | Histogram | |
|---|---|---|---|---|---|---|---|---|
| commission_errors | 42 | 0 | 18.5 | 8.4 | 0.0 | 18.0 | 43.0 | |
| commission_errors_r | 42 | 0 | 37.5 | 8.4 | 13.0 | 38.0 | 56.0 | |
| omission_errors | 48 | 0 | 10.1 | 20.8 | 0.0 | 6.0 | 224.0 | |
| go_accuracy | 164 | 0 | 95.4 | 9.4 | 0.0 | 97.3 | 100.0 | |
| nogo_accuracy | 129 | 0 | 66.9 | 15.4 | 20.4 | 68.4 | 100.0 | |
| overall_accuracy | 212 | 0 | 89.6 | 8.1 | 20.0 | 91.1 | 99.3 | |
| rt_go_avg | 502 | 1 | 327.3 | 27.6 | 251.4 | 328.0 | 416.8 | |
| rt_nogo_avg | 502 | 1 | 292.5 | 28.4 | 218.6 | 290.9 | 411.7 |
# and save it
gng_performance %>%
select(commission_errors:rt_nogo_avg) %>%
datasummary_skim(fun_numeric = list(Mean = Mean,
SD = SD, Min = Min,
Median = Median,
Max = Max
)) %>%
save_tt(here("03_output", "tables", "gng_performance.docx"), overwrite = TRUE)Plot the rt distribution during Go trials.
data_filtered %>%
filter(stimulus == 1 & !is.na(rt)) %>%
slice(1:3500) %>%
ggplot(aes(x = rt)) +
geom_density(alpha = 0.6, color = bp[5], fill = bp[6]) +
facet_wrap(~ subj_idx, ncol = 4) +
labs(x = "Reaction Time (ms)", y = element_blank(),
title = "Distribution of Reaction Times during Go Trials for Different Participant") +
guides(color = "none", alpha = "none", fill = "none") +
theme_ipsum_rc(plot_title_size = 14, grid = F) +
theme(legend.position = "bottom",
legend.title = element_blank(),
strip.text = element_text(size = 10))ggsave(here("03_output", "figures", "gng_sbj_rt_dist.png"), width = 9, height = 6, dpi = 300)Plot the overall distribution of commission errors
gng_performance %>%
ggplot(aes(x = commission_errors_r)) +
geom_histogram(binwidth = 1, fill = "steelblue", color = "white") +
theme_ipsum_rc()+
labs(
title = "Distribution of Reverse-scored Commission Errors",
x = "Commission Errors",
y = "Count"
)Reorder variables
gng_performance <- gng_performance %>%
select(subj_idx, commission_errors, commission_errors_r, omission_errors:rt_nogo_avg)Save data frames
# sum scores
write_csv(gng_performance, here("01_data", "scored", "data_gng_scores.csv"),
na = "", append = FALSE, col_names = TRUE)
# gng data
write_csv(data_filtered, here("01_data", "cleaned", "data_gng_filtered.csv"),
na = "", append = FALSE, col_names = TRUE)